from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import (
    QWidget, QTabWidget,
    QVBoxLayout, QHBoxLayout,
    QListWidget, QFrame,
    QListWidgetItem, QLabel, QPushButton
)

from common.equipment.interface import create_equip
from common.player.reference import Player
from common.quest import Quest, QuestStatus
from common.resources import Resource
from gui.reference import SIZE_WIDTH, SIZE_HEIGHT
from gui.signals import SIGNALS
from utils.db import DBSession
from utils.event_bus import EVENT_BUS
from utils.reference import message_box_information


class SubWidget(QWidget):
    def __init__(self, data):
        super().__init__()
        self.data = data
        self.selected_item: Quest | None = None

        main_layout = QHBoxLayout(self)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)

        left_frame = QFrame()
        left_frame.setFrameShape(QFrame.Shape.Box)
        left_frame.setLineWidth(1)

        left_layout = QVBoxLayout(left_frame)
        left_layout.setContentsMargins(0, 0, 0, 0)
        left_layout.setSpacing(0)

        self.list_view = QListWidget()
        self.list_view.setStyleSheet("QListWidget::item{height: 30px}")
        self.list_view.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
        left_layout.addWidget(self.list_view)
        self.list_view.itemClicked.connect(self.selected)

        right_frame = QFrame()
        right_frame.setFrameShape(QFrame.Shape.Box)
        right_frame.setLineWidth(1)

        right_layout = QVBoxLayout(right_frame)
        right_layout.setContentsMargins(0, 0, 0, 0)
        right_layout.setSpacing(0)

        self.right_title_label = QLabel()
        self.right_body_label = QLabel()
        self.right_body_label.setWordWrap(True)
        line = QFrame()
        line.setFrameShape(QFrame.Shape.HLine)
        line.setFrameShadow(QFrame.Shadow.Sunken)
        self.right_line = line

        right_layout.addWidget(self.right_title_label)
        right_layout.addWidget(self.right_line)
        right_layout.addStretch(1)
        right_layout.addWidget(self.right_body_label)
        right_layout.addStretch(1)

        rb_layout = QHBoxLayout()

        right_layout.addLayout(rb_layout)

        main_layout.addWidget(left_frame, 4)
        main_layout.addWidget(right_frame, 6)

        self.update_data()

    def clear_right(self):
        self.right_title_label.setText('')
        self.right_body_label.setText('')
        self.right_line.hide()

    def update_data(self):
        self.list_view.clear()
        self.clear_right()

        for quest_name in self.data:
            self.add_row(quest_name)

    def selected(self, item):
        self.clear_right()
        quest: Quest = item.data(Qt.ItemDataRole.UserRole)

        self.right_title_label.setText(f'<h1>{quest.title}</h1>')
        self.right_body_label.setText(quest.html())
        self.right_line.show()

    def add_row(self, quest):
        if isinstance(quest, str):
            quest: Quest = DBSession.quests[quest]

        item = QListWidgetItem()
        item.setData(Qt.ItemDataRole.UserRole, quest)
        self.list_view.addItem(item)
        self.list_view.setItemWidget(item, self.build_row_widget(quest))

    def build_row_widget(self, quest: Quest):
        return QLabel(quest.label())


# 进行中
class InProcessTabWidget(SubWidget):
    finish_quest = Signal(Quest)

    def build_row_widget(self, quest: Quest):
        widget = QWidget()
        layout = QHBoxLayout(widget)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        btn = QPushButton('完成')
        btn.setFixedHeight(30)
        btn.setEnabled(quest.ok)
        btn.clicked.connect(lambda: self.finish_quest.emit(quest))

        layout.addWidget(QLabel(quest.label()), 9)
        layout.addWidget(btn, 1)
        return widget


# 可接受
class AccessibleTabWidget(SubWidget):
    accept_quest = Signal(Quest)

    def build_row_widget(self, quest: Quest):
        widget = QWidget()
        layout = QHBoxLayout(widget)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        btn = QPushButton('接受')
        btn.setFixedHeight(30)
        btn.clicked.connect(lambda: self.accept_quest.emit(quest))

        layout.addWidget(QLabel(quest.label()), 9)
        layout.addWidget(btn, 1)
        return widget


class DialogQuest(QWidget):
    TAB_TITLES = ['进行中', '可接取', '已完成']

    def __init__(self, player: Player):
        super().__init__()

        self.player = player
        self.setWindowTitle("任务手册")
        self.setGeometry(200, 200, SIZE_WIDTH, SIZE_HEIGHT)
        self.setFixedSize(SIZE_WIDTH, SIZE_HEIGHT)
        self.tabs = QTabWidget(self)

        self.tab_in_process = InProcessTabWidget(player.quest_book.in_process)
        self.tab_in_process.finish_quest.connect(self.finish_quest)

        self.tab_accessible = AccessibleTabWidget(player.quest_book.accessible)
        self.tab_accessible.accept_quest.connect(self.accept_quest)

        self.tab_finish = SubWidget(player.quest_book.finished)

        self.tabs.addTab(self.tab_in_process, '进行中')
        self.tabs.addTab(self.tab_accessible, '可接取')
        self.tabs.addTab(self.tab_finish, '已完成')

        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(0, 0, 0, 0)  # 移除边距
        main_layout.setSpacing(0)  # 移除间距
        main_layout.addWidget(self.tabs)

        self.update_data()

    def update_data(self):
        quest_count = [
            len(self.player.quest_book.in_process),
            len(self.player.quest_book.accessible),
            len(self.player.quest_book.finished)
        ]
        for i, count in enumerate(quest_count):
            postfix = f'({count})' if count > 0 else ''
            self.tabs.setTabText(i, self.TAB_TITLES[i] + postfix)

        SIGNALS.change_quick_bar.emit()

    def accept_quest(self, quest: Quest):
        quest.status = QuestStatus.InProcess
        self.player.quest_book.accessible.remove(quest.name)
        self.player.quest_book.in_process.add(quest.name)

        if quest.check(self.player):
            quest.ok = True

        # 接取任务时 监听玩家行为
        EVENT_BUS.player_interaction.register(quest.player_interaction)

        self.tab_in_process.add_row(quest)
        self.tab_accessible.update_data()
        self.tab_accessible.selected_item = None

        self.update_data()

    def finish_quest(self, quest: Quest):
        if not quest.ok:
            return

        quest.do_finished(self.player)
        self.player.quest_book.in_process.remove(quest.name)
        self.player.quest_book.finished.add(quest.name)

        if self.player.quest_book.update():
            self.tab_accessible.update_data()

        self.tab_finish.add_row(quest)
        self.tab_in_process.update_data()
        self.tab_in_process.selected_item = None

        self.update_data()
        # 完成任务时 不再监听玩家行为
        EVENT_BUS.player_interaction.unregister(quest.player_interaction)

        if quest.rewards is None:
            return

        msg = ''
        delta_coin, delta_exp = 0, 0
        data = list()
        for key, item in quest.rewards.items():
            match key:
                case 'coin':
                    res_name = '金币'
                    delta_coin += item
                case 'exp':
                    res_name = '经验'
                    delta_exp += item
                case 'equipment':
                    equip: dict = DBSession.equipments[item]
                    res_name = equip['name']
                    data.append((1, key, create_equip(item, equip), 1))
                    item = 1
                case _:
                    res: Resource = DBSession.materials[key]
                    res_name = res.name

            msg += f'<span style="color:blue">{res_name}</span>x<span style="color:red">{item}</span>; '

        if self.player.bag.update(data):
            self.player.bag.coin += delta_coin
            self.player.state.add_exp(delta_exp)
            # 更新首页面板的金币数量
            SIGNALS.update_main_ui.emit()
            SIGNALS.send_message.emit(f'获得: {msg}')
        else:
            message_box_information('背包可用空间不足')
